package org.goodsmanager.aspect;

import com.alibaba.fastjson2.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.goodsmanager.entity.OperationLog;
import org.goodsmanager.entity.User;
import org.goodsmanager.service.OperationLogService;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

/**
 * 日志切面 - 记录Controller层方法执行日志
 *
 * @author Goods Manager System
 * @version 1.0.0
 */
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class LogAspect {

    private final OperationLogService operationLogService;

    private static final DateTimeFormatter DATE_TIME_FORMATTER =
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * 定义切点：拦截所有Controller
     */
    @Pointcut("execution(* org.goodsmanager.controller..*.*(..))")
    public void controllerPointcut() {
    }

    /**
     * 环绕通知：记录方法执行信息
     */
    @Around("controllerPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        
        // 获取用户信息
        User currentUser = null;
        try {
            ServletRequestAttributes attributes =
                    (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpSession session = attributes.getRequest().getSession(false);
                if (session != null) {
                    currentUser = (User) session.getAttribute("currentUser");
                }
            }
        } catch (Exception e) {
            log.warn("获取用户信息失败", e);
        }

        // 获取请求信息
        ServletRequestAttributes attributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes != null ? attributes.getRequest() : null;

        // 获取方法信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = method.getName();

        // 记录请求信息
        log.info("===========> 请求开始 <==========");
        log.info("请求时间: {}", LocalDateTime.now().format(DATE_TIME_FORMATTER));

        if (request != null) {
            log.info("请求URL: {} {}", request.getMethod(), request.getRequestURI());
            log.info("请求IP: {}", getIpAddress(request));
            log.info("请求来源: {}", request.getHeader("User-Agent"));
        }

        log.info("处理方法: {}.{}", className, methodName);

        // 记录请求参数（排除敏感信息）
        Object[] args = joinPoint.getArgs();
        String paramsStr = "";
        if (args != null && args.length > 0) {
            try {
                paramsStr = JSON.toJSONString(args);
                // 限制日志长度
                if (paramsStr.length() > 500) {
                    paramsStr = paramsStr.substring(0, 500) + "...";
                }
                log.info("请求参数: {}", paramsStr);
            } catch (Exception e) {
                log.warn("参数序列化失败", e);
            }
        }

        Object result = null;
        String operationStatus = "SUCCESS";
        String errorMessage = null;
        
        try {
            // 执行目标方法
            result = joinPoint.proceed();

            // 记录响应信息
            long endTime = System.currentTimeMillis();
            long executionTime = endTime - startTime;

            log.info("执行耗时: {} ms", executionTime);

            // 记录返回结果（限制长度）
            if (result != null) {
                try {
                    String resultStr = JSON.toJSONString(result);
                    if (resultStr.length() > 500) {
                        resultStr = resultStr.substring(0, 500) + "...";
                    }
                    log.info("返回结果: {}", resultStr);
                } catch (Exception e) {
                    log.info("返回结果: {}", result.getClass().getName());
                }
            }

            log.info("===========> 请求结束 <==========\n");

            // 性能警告
            if (executionTime > 3000) {
                log.warn("⚠️ 方法执行时间过长: {}ms，建议优化！", executionTime);
            }

            // 记录操作日志到数据库
            saveOperationLog(currentUser, request, className, methodName, paramsStr, 
                           operationStatus, errorMessage, executionTime);

            return result;

        } catch (Throwable e) {
            long endTime = System.currentTimeMillis();
            operationStatus = "ERROR";
            errorMessage = e.getMessage();
            if (errorMessage == null) {
                errorMessage = e.getClass().getSimpleName();
            }
            
            log.error("===========> 请求异常 <==========");
            log.error("执行耗时: {} ms", endTime - startTime);
            log.error("异常信息: ", e);
            log.error("===========> 异常结束 <==========\n");
            
            // 记录异常操作日志到数据库
            saveOperationLog(currentUser, request, className, methodName, paramsStr, 
                           operationStatus, errorMessage, endTime - startTime);
            
            throw e;
        }
    }

    /**
     * 保存操作日志到数据库
     */
    private void saveOperationLog(User currentUser, HttpServletRequest request, 
                                String className, String methodName, String paramsStr,
                                String operationStatus, String errorMessage, long executionTime) {
        try {
            OperationLog operationLog = new OperationLog();
            operationLog.setId(UUID.randomUUID().toString().replace("-", ""));
            
            // 设置用户信息
            if (currentUser != null) {
                operationLog.setUserId(currentUser.getId());
                operationLog.setUsername(currentUser.getUsername());
            }
            
            // 设置请求信息
            if (request != null) {
                operationLog.setRequestUrl(request.getRequestURI());
                operationLog.setRequestMethod(request.getMethod());
                operationLog.setIpAddress(getIpAddress(request));
                operationLog.setUserAgent(request.getHeader("User-Agent"));
            }
            
            // 设置操作信息
            operationLog.setOperationType(determineOperationType(methodName, request));
            operationLog.setModule(determineModule(className));
            operationLog.setDescription(generateDescription(methodName, request));
            operationLog.setRequestParams(paramsStr);
            operationLog.setStatus(operationStatus);
            operationLog.setErrorMessage(errorMessage);
            operationLog.setExecutionTime(executionTime);
            operationLog.setCreatedAt(LocalDateTime.now());
            
            // 异步保存日志，不阻塞主流程
            operationLogService.recordLog(operationLog);
        } catch (Exception e) {
            log.error("保存操作日志失败", e);
        }
    }

    /**
     * 根据方法名和请求确定操作类型
     */
    private String determineOperationType(String methodName, HttpServletRequest request) {
        if (methodName.startsWith("add") || methodName.startsWith("create") || methodName.startsWith("save")) {
            return "CREATE";
        } else if (methodName.startsWith("update") || methodName.startsWith("modify") || methodName.startsWith("edit")) {
            return "UPDATE";
        } else if (methodName.startsWith("delete") || methodName.startsWith("remove")) {
            return "DELETE";
        } else if (methodName.startsWith("login")) {
            return "LOGIN";
        } else if (methodName.startsWith("logout")) {
            return "LOGOUT";
        } else if (methodName.startsWith("export")) {
            return "EXPORT";
        } else if (methodName.startsWith("import")) {
            return "IMPORT";
        } else {
            return "QUERY";
        }
    }

    /**
     * 根据类名确定操作模块
     */
    private String determineModule(String className) {
        if (className.contains("ProductController")) {
            return "商品管理";
        } else if (className.contains("CategoryController")) {
            return "分类管理";
        } else if (className.contains("UserController")) {
            return "用户管理";
        } else if (className.contains("DashboardController")) {
            return "仪表盘";
        } else if (className.contains("AuthController")) {
            return "认证授权";
        } else {
            return "系统管理";
        }
    }

    /**
     * 生成操作描述
     */
    private String generateDescription(String methodName, HttpServletRequest request) {
        String operationType = determineOperationType(methodName, request);
        String module = determineModule(request != null ? request.getClass().getName() : "");
        
        return switch (operationType) {
            case "CREATE" -> "新增" + module;
            case "UPDATE" -> "更新" + module;
            case "DELETE" -> "删除" + module;
            case "LOGIN" -> "用户登录";
            case "LOGOUT" -> "用户登出";
            case "EXPORT" -> "导出" + module + "数据";
            case "IMPORT" -> "导入" + module + "数据";
            default -> "查询" + module;
        };
    }

    /**
     * 获取真实IP地址
     */
    private String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");

        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        // 处理多级代理的情况
        if (ip != null && ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }

        return ip;
    }
}